
package es.esi.gemde.modelvalidator.service.impl;

import java.util.Collection;
import java.util.List;
import java.util.Set;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.validation.EMFEventType;
import org.eclipse.emf.validation.IValidationContext;
import org.eclipse.emf.validation.model.ConstraintStatus;
import org.eclipse.emf.validation.model.IModelConstraint;

import es.esi.gemde.modelvalidator.service.IModelValidatorConstraint;


/**
 * The implementation of the {@link IModelValidatorConstraint}}
 *
 * @author Adrian Noguero (adrian.noguero@tecnalia.com)
 * @version 1.0
 * @since 1.0
 *
 */
public class ModelValidatorConstraint implements IModelValidatorConstraint {

	private IModelConstraint implementation;
	private String description;
	private String name;
	private String id;
	private String category;
	private EPackage targetedMetamodel;
	private EClass context;
	private ResourceType type;
	
	

	/**
	 * Constructor for the class. 
	 * It is not intended to be used outside this plug-in. Constraints should be created using implementations of {@link es.esi.gemde.modelvalidator.service.IConstraintFactory} 
	 *
	 *@param implementation the {@link IModelConstraint} implementation of the constraint in the EMF Validation Framework
	 *@param name the name of the constraint
	 *@param category the textual category of the constraint
	 *@param selectedMetamodel the {@link EPackage} defining the metamodel on which this constraint is applicable
	 *@see es.esi.gemde.modelvalidator.service.OCLConstraintFactory#createConstraint(String, String, int, String)
	 */
	public ModelValidatorConstraint (IModelConstraint implementation, String name, String category, EPackage selectedMetamodel, EClass context, ResourceType type) {
		this.implementation = implementation;
		this.name = name;
		this.category = category;
		this.targetedMetamodel = selectedMetamodel;
		this.type = type;
		this.context = context;
	}
	
	/**
	 * Constructor for the class. 
	 * It is not intended to be used outside this plug-in. Constraints should be created using implementations of {@link es.esi.gemde.modelvalidator.service.IConstraintFactory} 
	 *
	 *@param implementation the {@link IModelConstraint} implementation of the constraint in the EMF Validation Framework
	 *@param id the identifier of the constraint
	 *@param name the name of the constraint
	 *@param description a meaningful description of the constraint
	 *@param category the textual category of the constraint
	 *@param selectedMetamodel the {@link EPackage} defining the metamodel on which this constraint is applicable
	 *@see es.esi.gemde.modelvalidator.service.OCLConstraintFactory#createConstraint(String, String, int, String)
	 */
	public ModelValidatorConstraint (IModelConstraint implementation, String id,  String name, String description,  String category, EPackage selectedMetamodel, EClass context, ResourceType type) {
		this.id = id;
		this.description = description;
		this.implementation = implementation;
		this.name = name;
		this.category = category;
		this.targetedMetamodel = selectedMetamodel;
		this.type = type;
		this.context = context;
	}
	
	/**
	 * This class is a partial implementation of the {@link IValidationContext} interface as
	 * described in the tech_note "EMFValidationFramework_GuidelinesUsed.doc".
	 * 
	 * It is required for the validation of the constraint.
	 *
	 * @author Adri�n Noguero (adrian.noguero@esi.es)
	 * @version 1.0
	 * @since 1.0
	 *
	 */
	private class GEMDEValidationContext implements IValidationContext {

		private IModelConstraint constraint;
		private EObject target;
		
		public GEMDEValidationContext (IModelConstraint constraint, EObject target) {
			this.constraint = constraint;
			this.target = target;
		}
		
		/* (non-Javadoc)
		 * @see org.eclipse.emf.validation.IValidationContext#addResult(org.eclipse.emf.ecore.EObject)
		 */
		@Override
		public void addResult(EObject eObject) {
			// Not Used
		}

		/* (non-Javadoc)
		 * @see org.eclipse.emf.validation.IValidationContext#addResults(java.util.Collection)
		 */
		@Override
		public void addResults(Collection<? extends EObject> eObjects) {
			// Not Used
			
		}

		/* (non-Javadoc)
		 * @see org.eclipse.emf.validation.IValidationContext#createFailureStatus(java.lang.Object[])
		 */
		@Override
		public IStatus createFailureStatus(Object... messageArgument) {
			ConstraintStatus status = new ConstraintStatus(constraint, target, constraint.getDescriptor().getSeverity().toIStatusSeverity(), -1,  "The constraint '" + constraint.getDescriptor().getName() +"' failed on element " + target.toString(), null);
			return status;

		}

		/* (non-Javadoc)
		 * @see org.eclipse.emf.validation.IValidationContext#createSuccessStatus()
		 */
		@Override
		public IStatus createSuccessStatus() {
			ConstraintStatus status = new ConstraintStatus(constraint, target);
			return status;
		}

		/* (non-Javadoc)
		 * @see org.eclipse.emf.validation.IValidationContext#disableCurrentConstraint(java.lang.Throwable)
		 */
		@Override
		public void disableCurrentConstraint(Throwable exception) {
			// Not Used
			
		}

		/* (non-Javadoc)
		 * @see org.eclipse.emf.validation.IValidationContext#getAllEvents()
		 */
		@Override
		public List<Notification> getAllEvents() {
			// Not Used
			return null;
		}

		/* (non-Javadoc)
		 * @see org.eclipse.emf.validation.IValidationContext#getCurrentConstraintData()
		 */
		@Override
		public Object getCurrentConstraintData() {
			// Not Used
			return null;
		}

		/* (non-Javadoc)
		 * @see org.eclipse.emf.validation.IValidationContext#getCurrentConstraintId()
		 */
		@Override
		public String getCurrentConstraintId() {
			// Not Used
			return null;
		}

		/* (non-Javadoc)
		 * @see org.eclipse.emf.validation.IValidationContext#getEventType()
		 */
		@Override
		public EMFEventType getEventType() {
			// Not Used
			return null;
		}

		/* (non-Javadoc)
		 * @see org.eclipse.emf.validation.IValidationContext#getFeature()
		 */
		@Override
		public EStructuralFeature getFeature() {
			// Not Used
			return null;
		}

		/* (non-Javadoc)
		 * @see org.eclipse.emf.validation.IValidationContext#getFeatureNewValue()
		 */
		@Override
		public Object getFeatureNewValue() {
			// Not Used
			return null;
		}

		/* (non-Javadoc)
		 * @see org.eclipse.emf.validation.IValidationContext#getResultLocus()
		 */
		@Override
		public Set<EObject> getResultLocus() {
			// Not Used
			return null;
		}

		/* (non-Javadoc)
		 * @see org.eclipse.emf.validation.IValidationContext#getTarget()
		 */
		@Override
		public EObject getTarget() {
			return target;
		}

		/* (non-Javadoc)
		 * @see org.eclipse.emf.validation.IValidationContext#putCurrentConstraintData(java.lang.Object)
		 */
		@Override
		public Object putCurrentConstraintData(Object newData) {
			// Not Used
			return null;
		}

		/* (non-Javadoc)
		 * @see org.eclipse.emf.validation.IValidationContext#skipCurrentConstraintFor(org.eclipse.emf.ecore.EObject)
		 */
		@Override
		public void skipCurrentConstraintFor(EObject eObject) {
			// Not Used
			
		}

		/* (non-Javadoc)
		 * @see org.eclipse.emf.validation.IValidationContext#skipCurrentConstraintForAll(java.util.Collection)
		 */
		@Override
		public void skipCurrentConstraintForAll(Collection<?> eObjects) {
			// Not Used
			
		}
		
	}
	
	/* (non-Javadoc)
	 * @see es.esi.gemde.modelvalidator.service.IModelValidatorConstraint#getCategory()
	 */
	@Override
	public String getCategory() {
		return category;
	}

	/* (non-Javadoc)
	 * @see es.esi.gemde.modelvalidator.service.IModelValidatorConstraint#getName()
	 */
	@Override
	public String getName() {
		return name;
	}

	/* (non-Javadoc)
	 * @see es.esi.gemde.modelvalidator.service.IModelValidatorConstraint#validate()
	 */
	@Override
	public IStatus validate(EObject onTarget) {
		// Create a context
		GEMDEValidationContext ctx = new GEMDEValidationContext(implementation, onTarget);
		// Execute validation and return the result
		return implementation.validate(ctx);
	}

	/* (non-Javadoc)
	 * @see es.esi.gemde.modelvalidator.service.IModelValidatorConstraint#getSeverity()
	 */
	@Override
	public int getSeverity() {
		return implementation.getDescriptor().getSeverity().toIStatusSeverity();
	}

	/* (non-Javadoc)
	 * @see es.esi.gemde.modelvalidator.service.IModelValidatorConstraint#targetsTypeOf(org.eclipse.emf.ecore.EObject)
	 */
	@Override
	public boolean targetsTypeOf(EObject target) {
		return implementation.getDescriptor().targetsTypeOf(target);
	}

	/* (non-Javadoc)
	 * @see es.esi.gemde.modelvalidator.service.IModelValidatorConstraint#getImplementation()
	 */
	@Override
	public String getBody() {
		return implementation.getDescriptor().getBody();
	}

	/* (non-Javadoc)
	 * @see es.esi.gemde.modelvalidator.service.IModelValidatorConstraint#getApplicationMetamodel()
	 */
	@Override
	public EPackage getApplicationMetamodel() {
		return targetedMetamodel;
	}

	/* (non-Javadoc)
	 * @see es.esi.gemde.modelvalidator.service.IModelValidatorConstraint#isProtected()
	 */
	@Override
	public boolean isProtected() {
		return type.equals(ResourceType.PROTECTED);
	}

	/* (non-Javadoc)
	 * @see es.esi.gemde.modelvalidator.service.IModelValidatorConstraint#getApplicationContext()
	 */
	@Override
	public EClass getApplicationContext() {
		return context;
	}

	/* (non-Javadoc)
	 * @see es.esi.gemde.modelvalidator.service.IModelValidatorConstraint#getDescription()
	 */
	@Override
	public String getDescription() {
		return description;
	}

	/* (non-Javadoc)
	 * @see es.esi.gemde.modelvalidator.service.IModelValidatorConstraint#getIdentifier()
	 */
	@Override
	public String getIdentifier() {
		return id;
	}

	@Override
	public ResourceType getResourceType() {
		return type;
	}

}
